package de.tum.icuproject;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import de.tum.icuproject.model.Player;
import de.tum.icuproject.model.Session;
import de.tum.icuproject.network.MDCClient;
import de.tum.icuproject.persistence.SessionRepository;
import de.tum.icuproject.persistence.couchdb.SessionRepositoryImpl;
import de.tum.icuproject.utils.AppUtils;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Toast;

/**
 * The Parameters Panel allows setting the game parameters and starting/stopping the game.
 * 
 * @author stefanoturchetta
 *
 */
public class ParameterFragment extends Fragment implements Subscriber {

	// Store the app's shared preferences repository:
	private SharedPreferences mPrefs;

	private String host;
	private int port;

	private MDCClient mdcClient;

	private SeekBar seekbarTargetHR;
	private TextView textViewTargetHRValue;
	private SeekBar seekbarTargetLoad;
	private TextView textViewTargetLoadValue;
	private SeekBar seekbarTargetSpeed;
	private TextView textViewTargetSpeedValue;

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View rootView = inflater.inflate(R.layout.fragment_parameter,
				container, false);

		// Get the elements from the layout:
		seekbarTargetHR = (SeekBar) rootView.findViewById(R.id.seekbarTargetHR);
		textViewTargetHRValue = (TextView) rootView.findViewById(R.id.textViewTargetHRValue);
		seekbarTargetLoad = (SeekBar) rootView.findViewById(R.id.seekbarTargetLoad);
		textViewTargetLoadValue = (TextView) rootView.findViewById(R.id.textViewTargetLoadValue);
		seekbarTargetSpeed = (SeekBar) rootView.findViewById(R.id.seekbarTargetSpeed);
		textViewTargetSpeedValue = (TextView) rootView.findViewById(R.id.textViewTargetSpeedValue);

		// Set default text:
		textViewTargetHRValue.setText("0 bpm");
		textViewTargetLoadValue.setText("0 watts");
		textViewTargetSpeedValue.setText("0 rpm");

		seekbarTargetHR.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				textViewTargetHRValue.setText(progress + " bpm");
			}

			public void onStartTrackingTouch(SeekBar seekBar) {}

			public void onStopTrackingTouch(SeekBar seekBar) {
				sendParameters();
			}
		});

		seekbarTargetLoad.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				textViewTargetLoadValue.setText(progress + " watts");
			}

			public void onStartTrackingTouch(SeekBar seekBar) {}

			public void onStopTrackingTouch(SeekBar seekBar) {
				sendParameters();
			}
		});

		seekbarTargetSpeed.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				textViewTargetSpeedValue.setText(progress + " rpm");
			}

			public void onStartTrackingTouch(SeekBar seekBar) {}

			public void onStopTrackingTouch(SeekBar seekBar) {
				sendParameters();
			}
		});

		Button btnStart = (Button) rootView.findViewById(R.id.buttonStart);
		btnStart.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				startGame(v);
			}
		});

		Button btnStop = (Button) rootView.findViewById(R.id.buttonStop);
		btnStop.setEnabled(false);
		btnStop.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				stopGame(v);
			}
		});

		// Initialize shared preferences:
		this.mPrefs = getActivity().getPreferences(Context.MODE_PRIVATE);

		// Initialize host and port with stored preferred values:
		this.initHostAndPort(rootView);

		return rootView;
	}

	/**
	 * Initializes host and port.
	 * @param rootView
	 */
	private void initHostAndPort(View rootView) {
		EditText editTxtHost = (EditText) rootView.findViewById(R.id.editTextHost);
		String host = this.mPrefs.getString(AppUtils.HOST, "");
		editTxtHost.setText(host);
		EditText editTxtPort = (EditText) rootView.findViewById(R.id.editTextPort);
		String port = this.mPrefs.getString(AppUtils.PORT, "");
		editTxtPort.setText(port);
	}

	/**
	 * Gets values from the view and store them into shared preferences.
	 */
	private void getHostAndPort() {
		// Get editor of shared preferences:
		Editor editor = this.mPrefs.edit();
		EditText editTxtHost = (EditText) getView().findViewById(R.id.editTextHost);
		EditText editTxtPort = (EditText) getView().findViewById(R.id.editTextPort);
		String host = editTxtHost.getText().toString();
		if (host != null && !host.equals("")) {
			this.host = host;
		} else {
			this.host = AppUtils.DEFAULT_HOST;
		}
		String port = editTxtPort.getText().toString();
		if (port != null && !port.equals("")) {
			this.port = Integer.parseInt(port);
		} else {
			this.port = AppUtils.DEFAULT_PORT;
		}
		editor.putString(AppUtils.HOST, this.host);
		editor.putString(AppUtils.PORT, String.valueOf(this.port));
		editor.commit();
	}

	private void sendParameters() {
		if (mdcClient != null) {
			List<Integer> parameters = this.getParameters();
			mdcClient.sendParameters(parameters);
		}
	}

	private List<Integer> getParameters() {
		List<Integer> parameters = new ArrayList<Integer>(3);
		parameters.add(0, seekbarTargetHR.getProgress());
		parameters.add(1, seekbarTargetSpeed.getProgress());
		parameters.add(2, seekbarTargetLoad.getProgress());
		return parameters;
	}

	private void startGame(View v) {
		MainActivity mainActivity = (MainActivity) this.getActivity();
		// Get the clientHandler from the main activity:
		Handler clientHandler = mainActivity.getClientHandler();
		if (clientHandler != null) {
			// Get the current player from the PlayerFragment:
			Player player = mainActivity.getCurrentPlayer();
			if (player != null) {
				SessionRepository sessionRepo = new SessionRepositoryImpl(this);
				// Generate a session id.
				// TODO: as agreed activityId is always 1 for now.
				sessionRepo.generateSessionId(player.getPlayerId(), 1);
			} else {
				Toast.makeText(mainActivity, "You must select a player before starting the game!", Toast.LENGTH_LONG).show();
			}
		}
	}

	private void stopGame(View v) {
		if (this.mdcClient != null) {
			// Stop the thread.
			this.mdcClient.sendStop();
			// v is the button stop.
			v.setEnabled(false);
			// Enable button start:
			Button btnStart = (Button) getView().findViewById(R.id.buttonStart);
			btnStart.setEnabled(true);
		}
	}

	@Override
	public void setCurrentPlayer(Player player) {
	}

	@Override
	public void setPlayerId(int playerId) {
	}

	@Override
	public void confirmInsertion(boolean confirm) {
		Toast.makeText(getActivity(), "Inserted session ?= " + confirm, Toast.LENGTH_SHORT).show();
	}

	@Override
	public void confirmUpdate(boolean confirm) {
	}

	@Override
	public void confirmDeletion(boolean confirm) {
	}

	@Override
	public void setSessionId(int sessionId) {		
		MainActivity mainActivity = (MainActivity) this.getActivity();
		// Get the clientHandler from the main activity:
		Handler clientHandler = mainActivity.getClientHandler();
		if (clientHandler != null) {
			// Get the current player from the PlayerFragment:
			Player player = mainActivity.getCurrentPlayer();
			if (player != null) {
				// Store a new session to the database:
				this.storeSession(sessionId, player.getPlayerId());
				this.sendInitialParameters(clientHandler, player.getPlayerId(), sessionId);
			}
		}
	}

	private void sendInitialParameters(Handler clientHandler, int playerId, int sessionId) {
		// Get host and port from the fragment:
		this.getHostAndPort();
		// Initialize mdcClient:
		this.mdcClient = new MDCClient(this.host, this.port, clientHandler);
		// Get initial parameters to send:
		List<Integer> parameters = this.getParameters();
		// Start the thread:
		this.mdcClient.sendStart(playerId, sessionId, parameters);
		// Disable start button:
		Button btnStart = (Button) getView().findViewById(R.id.buttonStart);
		btnStart.setEnabled(false);
		// Enable stop button:
		Button btnStop = (Button) getView().findViewById(R.id.buttonStop);
		btnStop.setEnabled(true);
	}

	private void storeSession(int sessionId, int playerId) {
		Date now = new Date(System.currentTimeMillis());
		DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.ENGLISH);
		String datetime = df.format(now);
		// ActivityId is always 1 for now!
		Session session = new Session(sessionId, playerId,
				1, datetime);
		SessionRepository sessionRepo = new SessionRepositoryImpl(this);
		sessionRepo.insert(session);
	}

	@Override
	public void setCurrentSession(Session session) {
	}

	@Override
	public Player getCurrentPlayer() {
		MainActivity mainActivity = (MainActivity) getActivity();
		return mainActivity.getCurrentPlayer();
	}
}
